# 装饰器

# 由于函数也是一个对象，而且函数对象可以被赋值给变量，所以，通过变量也能调用该函数
def now():
    print('2025-07-22')
f = now
f()
# 函数对象有一个 __name__ 属性（注意：是前后各两个下划线），可以拿到函数的名字
print(now.__name__)
print(f.__name__)
print('-' * 100)

# 现在，假设我们要增强 now() 函数的功能，比如，在函数调用前后自动打印日志，但又不希望修改now()函数的定义，这种代码运行期间动态增加功能的方式，称之为“装饰器” (Decorator)
# 本质上，decorator 就是一个返回函数的高阶函数。所以，我们要定义一个能打印日志的decorator, 可以定义如下：

# log就是一个闭包函数
def log(func):
    def wrapper(*args, **kwargs):
        print('call %s():' % func.__name__)
        return func(*args, **kwargs)
    return wrapper

@log
def now():
    print('2025-07-22')
now()
print('-' * 100)

# 如果decorator 本身需要传入参数，那就需要编写一个返回decorator的高阶函数，写出来会更复杂。比如，要定义log的文本：
def log(text):
    def decorator(func):
        def wrapper(*args, **kwargs):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kwargs)
        return wrapper
    return decorator
# 这个3层嵌套的decorator用法如下：
@log('execute')
def now():
    print('2025-07-22')
now()
'''
输出结果：
execute now():
2025-07-22

我们来剖析上面的语句，首先执行log('execute')，返回的是decorator函数，再调用返回的函数，参数是now函数，返回值最终是wrapper函数。
以上两种decorator的定义都没有问题，但还差最后一步。因为我们讲了函数也是对象，它有__name__等属性，但你去看经过decorator装饰之后的函数，它们的__name__已经从原来的'now'变成了'wrapper'：
'''